package com.ada.codec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.PureJavaCrc32;
import org.apache.commons.codec.digest.PureJavaCrc32C;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

public class CheckSumApp {
    public static long checksumInputStream(String filepath) throws IOException {
        InputStream inputStreamn = new FileInputStream(filepath);
        Checksum crc = new CRC32();

        int cnt;

        while ((cnt = inputStreamn.read()) != -1) {
            crc.update(cnt);
        }
        return crc.getValue();
    }

    private static String getCrc(byte[] data) {
        int high;
        int flag;

        // 16位寄存器，所有数位均为1
        int wcrc = 0xffff;
        for (int i = 0; i < data.length; i++) {
            // 16 位寄存器的高位字节
            high = wcrc >> 8;
            // 取被校验串的一个字节与 16 位寄存器的高位字节进行“异或”运算
            wcrc = high ^ data[i];

            for (int j = 0; j < 8; j++) {
                flag = wcrc & 0x0001;
                // 把这个 16 寄存器向右移一位
                wcrc = wcrc >> 1;
                // 若向右(标记位)移出的数位是 1,则生成多项式 1010 0000 0000 0001 和这个寄存器进行“异或”运算
                if (flag == 1) {
                    wcrc ^= 0xa001;
                }
            }
        }

        return Integer.toHexString(wcrc);
    }

    public static long checksumString(String text) throws IOException {

        StringReader reader = new StringReader(text);
        //PureJavaCrc32 PureJavaCrc32C
        Checksum crc = new CRC32();

        int cnt;

        while ((cnt = reader.read()) != -1) {
            crc.update(cnt);
        }
        return crc.getValue();
    }

    public static long checksumBufferedInputStream(String filepath) throws IOException {
        InputStream inputStream = new BufferedInputStream(new FileInputStream(filepath));

        CRC32 crc = new CRC32();

        int cnt;

        while ((cnt = inputStream.read()) != -1) {
            crc.update(cnt);
        }
        return crc.getValue();
    }

    public static long checksumRandomAccessFile(String filepath) throws IOException {
        RandomAccessFile randAccfile = new RandomAccessFile(filepath, "r");
        long length = randAccfile.length();
        CRC32 crc = new CRC32();

        for (long i = 0; i < length; i++) {
            randAccfile.seek(i);
            int cnt = randAccfile.readByte();
            crc.update(cnt);
        }
        return crc.getValue();
    }

    public static long checksumMappedFile(String filepath) throws IOException {
        FileInputStream inputStream = new FileInputStream(filepath);
        FileChannel fileChannel = inputStream.getChannel();

        int len = (int) fileChannel.size();

        MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, len);

        CRC32 crc = new CRC32();

        for (int cnt = 0; cnt < len; cnt++) {

            int i = buffer.get(cnt);
            crc.update(i);
        }
        return crc.getValue();
    }

    public static void main(String[] args) throws IOException {
        //2372962152 3200196210 2372962152
        System.out.println(checksumString("ada"));
        byte[] xx = Base64.decodeBase64("6ZmV6KW/5ZCM57qz5L+h5oGv5oqA5pyv5pyJ6ZmQ5YWs5Y+4PC8+OTE2MTAxMzE3ODY5OTUzNzlDPC8+PC8+PC8+NUY5Qw==");
        System.out.println(new String(xx));
        System.out.println(getCrc("陕西同纳信息技术有限公司</>91610131786995379C</></></>".getBytes()));

    }

    private static void filecheck() throws IOException {
        String filepath = "D:/新增通讯录.xls";

        System.out.println("Input Strea method:");

        long start_timer = System.currentTimeMillis();
        long crc = checksumInputStream(filepath);
        long end_timer = System.currentTimeMillis();

        System.out.println(Long.toHexString(crc));
        System.out.println((end_timer - start_timer) + " ms");
        System.out.println("///////////////////////////////////////////////////////////");

        System.out.println("Buffered Input Stream method:");
        start_timer = System.currentTimeMillis();
        crc = checksumBufferedInputStream(filepath);
        end_timer = System.currentTimeMillis();
        System.out.println(Long.toHexString(crc));
        System.out.println((end_timer - start_timer) + " ms");

        System.out.println("///////////////////////////////////////////////////////////");

        System.out.println("Random Access File method:");
        start_timer = System.currentTimeMillis();
        crc = checksumRandomAccessFile(filepath);
        end_timer = System.currentTimeMillis();
        System.out.println(Long.toHexString(crc));
        System.out.println((end_timer - start_timer) + " ms");

        System.out.println("///////////////////////////////////////////////////////////");

        System.out.println("Mapped File method:");
        start_timer = System.currentTimeMillis();
        crc = checksumMappedFile(filepath);
        end_timer = System.currentTimeMillis();
        System.out.println(Long.toHexString(crc));
        System.out.println((end_timer - start_timer) + " ms");
    }
}

